package com.ifonly.datatables;

import com.google.common.base.Strings;
import com.ifonly.datatables.model.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;


/**
 * <p>
 * . DataTables 请求参数的封装
 * </p>
 *
 * @author Jerry Ou
 * @version 1.0 2015-08-31 13:43
 * @since JDK 1.6
 */
public class DTRequest {
    /**
     * 参数由前台传入，控制查询数据是否由自己控制，还是 DataTables 组件控制，true 表示自己控制
     */
    private boolean c_filter;
    /**
     * 表示 DataTables 请求次数，返回给 DataTables
     */
    private int draw;
    /**
     * 查询起始记录条目
     */
    private int start;
    /**
     * 查询总数
     */
    private int length;
    /**
     * 查询列封装
     */
    private List<DTColumn> columns;
    /**
     * DataTables查询条件
     */
    private DTSearch search;
    /**
     * 排序字段列表
     */
    private List<DTOrder> orders;
    /**
     * 自己控制查询字段列表
     */
    private List<Filter> filters;

    /**
     * 构造方法
     */
    private DTRequest() {

    }

    /**
     * 创建 DTRequest 对象
     * 从 HttpServletRequest 对象中获取请求参数，封装成 DTRequest 对象
     *
     * @param request HttpServletRequest 对象
     * @return DTRequest 对象
     */
    public static DTRequest newInstance(HttpServletRequest request) {
        DTRequest dtRequest = new DTRequest();

        //获取 c_filter
        dtRequest.c_filter = !DTUtils.strNullOrEmpty(request.getParameter(DTConstants.C_FILTER));
        //获取 draw
        dtRequest.draw = DTUtils.parseInt(request.getParameter(DTConstants.DRAW));
        //获取 start
        dtRequest.start = DTUtils.parseInt(request.getParameter(DTConstants.START));
        //获取 length
        dtRequest.length = DTUtils.parseInt(request.getParameter(DTConstants.LENGTH));
        //获取 search
        dtRequest.search = new DTSearch(
                request.getParameter(DTConstants.SEARCH_VALUE),
                DTUtils.parseBoolean(request.getParameter(DTConstants.SEARCH_REGEX))
        );

        // columns orders filters 是通过参数名的前缀来判读的，需要遍历所有请求参数
        dtRequest.columns = new ArrayList<DTColumn>();
        dtRequest.orders = new ArrayList<DTOrder>();
        dtRequest.filters = new ArrayList<Filter>();

        Enumeration<String> names = request.getParameterNames();

        /*Enumeration<String> namesEnumeration = request.getParameterNames();
        List<String> list = Collections.list(namesEnumeration);
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        Iterator<String> names = list.iterator();*/

        while (names.hasMoreElements()) {
            String name = names.nextElement();
            String value = request.getParameter(name);

            if (name.startsWith(DTConstants.COLUMNS_PREFIX)) { //COLUMN 前缀
                int index = DTUtils.parseInt(DTUtils.columnsIndexFromName(name));
                if (index >= dtRequest.columns.size()) {
                    //4        0
                    dtRequest.columns = DTUtils.newList(dtRequest.columns, index + 1, index);
                }

                DTColumn dtColumn = null;
                if (dtRequest.columns.size() > index) {
                    dtColumn = dtRequest.columns.get(index);
                }
                if (dtColumn == null) {
                    DTColumn.Search search = new DTColumn.Search(
                            request.getParameter(String.format(DTConstants.COLUMNS_$_SEARCH_VALUE, index)),
                            DTUtils.parseBoolean(request.getParameter(String.format(DTConstants.COLUMNS_$_SEARCH_REGEX, index)))
                    );
                    if (!Strings.isNullOrEmpty(request.getParameter(
                            String.format(DTConstants.COLUMNS_$_DATA, index)))) {
                        dtColumn = new DTColumn(request.getParameter(
                                String.format(DTConstants.COLUMNS_$_DATA, index)),
                                request.getParameter(String.format(DTConstants.COLUMNS_$_NAME, index)),
                                DTUtils.parseBoolean(request.getParameter(String.format(DTConstants.COLUMNS_$_SEARCHABLE, index))),
                                DTUtils.parseBoolean(request.getParameter(String.format(DTConstants.COLUMNS_$_ORDERABLE, index))),
                                search
                        );

                        dtRequest.columns.set(index, dtColumn);
                    }

                }
            } else if (name.startsWith(DTConstants.ORDER_PREFIX)) { //ORDER 前缀
                int index = DTUtils.parseInt(DTUtils.orderIndexFromName(name));
                if (index >= dtRequest.orders.size()) {
                    dtRequest.orders = DTUtils.newList(dtRequest.orders, index + 1, index);
                }

                DTOrder dtOrder = null;
                if (dtRequest.orders.size() > index) {
                    dtOrder = dtRequest.orders.get(index);
                }
                if (dtOrder == null) {
                    dtOrder = new DTOrder(
                            DTUtils.parseInt(request.getParameter(String.format(DTConstants.ORDER_$_COLUMN, index))),
                            request.getParameter(String.format(DTConstants.ORDER_$_DIR, index))
                    );
                    dtRequest.orders.set(index, dtOrder);
                }
            } else {
                if (dtRequest.c_filter && name.startsWith(DTConstants.C_FILTER_PREFIX)) { //自定义过滤前缀
                    if (!DTUtils.strNullOrEmpty(value)) {
                        String[] param_array = name.split(DTConstants.C_FILTER_SPLIT);
                        if (param_array.length >= 2) {
                            String c_filter_name = param_array[1];
                            String condition = param_array.length == 2 ? Condition.EQ.toString() : param_array[2];
                            Condition query_condition;
                            if (DTUtils.strNullOrEmpty(condition)) {
                                query_condition = Condition.EQ;
                            } else {
                                String conditionUpperCase = condition.toUpperCase();
                                query_condition = Condition.valueOf(conditionUpperCase);
                            }
                            switch (query_condition) {
                                case AND:
                                    break;
                                case BETWEEN:
                                    String two_param = name.replace(Condition.BETWEEN.toString(), "AND");
                                    String value2 = request.getParameter(two_param);
                                    dtRequest.filters.add(new Filter(c_filter_name, value, value2, query_condition));
                                    break;
                                case LIKE:
                                    dtRequest.filters.add(new Filter(c_filter_name, DTUtils.like(value), query_condition));
                                    break;
                                case LLIKE:
                                    dtRequest.filters.add(new Filter(c_filter_name, DTUtils.llike(value), query_condition));
                                    break;
                                case RLIKE:
                                    dtRequest.filters.add(new Filter(c_filter_name, DTUtils.rlike(value), query_condition));
                                    break;
                                default:
                                    dtRequest.filters.add(new Filter(c_filter_name, value, query_condition));
                            }
                        }
                    }
                }
            }
        }

        return dtRequest;
    }


    public int getDraw() {
        return draw;
    }

    public int getStart() {
        return start;
    }

    public int getLength() {
        return length;
    }

    public List<DTColumn> getColumns() {
        return columns;
    }

    public DTSearch getSearch() {
        return search;
    }

    public List<DTOrder> getOrders() {
        return orders;
    }

    public List<Filter> getFilters() {
        return filters;
    }

    public boolean isC_filter() {
        return c_filter;
    }

    @Override
    public String toString() {
        return "DTRequest{" +
                "c_filter=" + c_filter +
                ", draw=" + draw +
                ", start=" + start +
                ", length=" + length +
                ", columns=" + columns +
                ", search=" + search +
                ", orders=" + orders +
                ", filters=" + filters +
                '}';
    }
}
